package serverSelction;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class Helper {
	
	int k;
	int n;
	int generator[][];
	
	
	public Helper(int k, int n) {
		super();
		this.k = k;
		this.n = n;
		generator= new int[k][n];
		generator= createGeneratorMatrix();
	}
	private int[][] createGeneratorMatrix() {
		Random random = new Random();
		 int[][] matrix = new int[k][n];
		for (int outerIndex = 0; outerIndex < matrix.length; outerIndex++) {
			for (int innerIndex = 0; innerIndex < matrix[outerIndex].length; innerIndex++) {
				if (random.nextDouble() < 0.5) {
					matrix[outerIndex][innerIndex] = 1;
				} else {
					matrix[outerIndex][innerIndex] = 0;
				}
			}
		}
		int[][] transpose= new int[n][k];
		transpose=matrixTranspose(matrix);
		return transpose;
	}
	
	
	private int[][] matrixTranspose(int[][] generator) {
		int[][] transpose;
		int rows = k;
		int cols = n;
		transpose = new int[cols][rows];

		for (int h = 0; h < rows; h++) {
			for (int i = 0; i < cols; i++) {
				transpose[i][h] = generator[h][i];
			}
		}

		return transpose;
	}
	
	
	

	public int[] onTheFlyServer(int[] serverIndex) {
		
		int currServer = 0;
		int emptyRows = k - 1;
		int[] eqn = new int[k];
		int eqOnes = 0;
		int leftMost = 0;
		int s = 0;
		int i = -1;
		
		emptyRows = n;
		int[][] G= new int[k][k];
		
		List<Integer> srvrInstd= new ArrayList<Integer>();
		int[] numOnes= new int[k];
		
		for( int l=0;l<k ;l++){
			for ( int j=0;j<k ;j++){
				G[l][j]=0;
			}
		}

		/*
		 * array to keep track of which server index is finally actually
		 * inserted at which position within the G matrix
		 */

		i = 0;
		while (emptyRows > 0 && i <= serverIndex.length-1) {
			currServer = serverIndex[i];
			eqOnes = 0;
			leftMost = 0;
			s = 0;
			/*
			 * eqn = extract one row from the generator matrix 
			 */
			for (int j = 0; j < k; j++) {
				eqn[j] = generator[serverIndex[i]][j];

				if (eqn[j] == 1) {
					eqOnes++;
					if (leftMost == 0) {
						leftMost = 1;
						s = j;
					}
				}
			}
			while (G[s][s] == 1 && eqOnes > 0) {
				if (eqOnes >= numOnes[s]) {
					/*
					 * eqn'=xor G[s] and eqn
					 */
					for (int l = 0; l < k; l++) {
						eqn[l] = (eqn[l] + G[s][l]) % 2;
					}
				} else {
					/*
					 * swap eqn and G[s]
					 */
					for (int l = 0; l < k; l++) {
						int temp = eqn[l];
						eqn[l] = G[s][l];
						G[s][l] = temp;
					}
					numOnes[s] = eqOnes;

				}
				/*
				 * calculate left most 1 in eqn and degree of eqn'( numOfOnes)
				 */
				leftMost = 0;
				s = 0;
				eqOnes = 0;
				int l = 0;
				while (l < k) {
					if (eqn[l] == 1) {
						if (leftMost == 0) {
							s = l;
							leftMost++;
						}
						eqOnes++;
					}
					l++;
				}
			}
			if (eqOnes > 0) {

				/*
				 * add eqn to G[s], gDegree=numOfOnes, emptyRows=emptyRows-1
				 */
				for (int m = 0; m < k; m++) {
					G[s][m] = eqn[m];
				}
				//InitialServerSet.encodedFragments.set(s, tempBitSet);
				numOnes[s] = eqOnes;
				emptyRows = emptyRows - 1;
				srvrInstd.add(currServer);
//				srvrInstd.add(s,currServer);
//				serverInserted.add(s, currServer);
//				serverInserted[s] = currServer;
			} else {
			}
			/*
			 * discard equation if has all 0s or all 1s
			 */
			i++;
		}
		
//		for ( i=0;i<k;i++){
//			System.out.println(" ");
//			for ( int j=0;j<k;j++){
//				System.out.print(" "+G[i][j]);
//			}
//		}
		int[] serverInserted= new int[srvrInstd.size()];
	     i=0;
		for(int s1 : srvrInstd){
			serverInserted[i++]=s1;
		}
		//return srvrInstd.toArray(serverInserted);
		return serverInserted;
	}
	
	List<ServerInfo> listOfServers= new ArrayList<ServerInfo>();
	public void generateDateRateOfServers(){		
		for ( int i=0;i<n;i++){
			listOfServers.add( new ServerInfo(i,(int)(200+Math.random()*200)));
		}
	}
	
	public int[] dataRateOfServers(int[] availability){
	    generateDateRateOfServers();
	    System.out.println();
	   int i=0;
	    for ( int serverIndex: availability){
	    	if (serverIndex==0){
	    		listOfServers.set(i, new ServerInfo(i, 0) );
	    	}
	    	i=i+1;
	    }
		ServerInfoComparator com  = new ServerInfoComparator();
		double start=System.nanoTime();
		Collections.sort(listOfServers,com);
		double end=System.nanoTime();
		System.out.println(end-start);
	    List<Integer> servers = new ArrayList<Integer>();
		i=0;
		//TODO add condition here so that the servers which are down are not inserted
		for ( ServerInfo s : listOfServers){
			if(s.getServerDataRate()!=0){
			//servers.add(i,s.getServerId());
				servers.add(s.getServerId());
			}
			i=i+1;
		}
		i=0;
		int[] ret= new int[servers.size()];
	   for( int s : servers){
		   ret[i++]=s;
	   }
		return ret;
		
	}
	
	
	
	public int gaussianElimination(int[] sourceIndex) {
		// ArrayList<BitSet> ec = encodedFragments;
		// System.out.println(" original matrix");
		// printMatrix(G, k, N_new);
		// this.encodedFragments= encodedFragments;
        int result =0;
		int[][] newGenerator = new int[k][k];
		int l = 0;
		for (int i=0;i<k;i++) {
//			System.out.println(" GE"+sourceIndex[i]);
			for (int j = 0; j < k; j++) {
				newGenerator[l][j] = generator[sourceIndex[i]][j];
			}
			l++;
		}
//		printMatrix(newGenerator, k, k);

		int n = k;
		int N = k;
		// ArrayList<String> decodedString = new ArrayList<String>();
		for (int p = 0; p < n; p++) {
			int max = p;
			for (int i = p + 1; i < N; i++) {
				if (Math.abs(newGenerator[i][p]) > Math
						.abs(newGenerator[max][p])) {
					max = i;
				}
			}
			int[] temp = newGenerator[p];
			newGenerator[p] = newGenerator[max];
			newGenerator[max] = temp;

			// System.out.println(" diagonal matrix");
			// printMatrix(G, k, N_new);

			if (Math.abs(newGenerator[p][p]) != 1) {
				return 0;
//				throw new RuntimeException(
//						"Matrix is singular or nearly singular");
			}

			for (int i = p + 1; i < N; i++) {
				int alpha = Math.abs(-(newGenerator[i][p] / newGenerator[p][p]));
			
				for (int j = p; j < n; j++) {
					newGenerator[i][j] = newGenerator[i][j]
							^ (alpha & newGenerator[p][j]);
				}
			}
//			System.out.println(" lower triangle is decode n the fly");
//			printMatrix(newGenerator, k, k);
			for (int i = 0; i <= p - 1; i++) {
				int alpha =Math.abs( -(newGenerator[i][p] / newGenerator[p][p]));
				
				for (int j = p; j < n; j++) {
					newGenerator[i][j] = newGenerator[i][j]
							^ (alpha & newGenerator[p][j]);
				}
			}
			// System.out.println(" upper triangle");
			// printMatrix(newGenerator, k, N_new);
		}
		result++;
//		printMatrix(newGenerator, k, k);
		return result;
	}
	
	

}
